<?php
/**
 * 图片处理类库.
 *
 * 包括图片压缩和图片加水印
 *
 * @author xiaoxia.xu <xiaoxia.xuxx@aliyun-inc.com>
 * @copyright ©2003-2103 phpwind.com
 * @license http://www.windframework.com
 *
 * @version $Id: WindImage.php 2973 2011-10-15 19:22:48Z yishuo $
 */
class WindImage
{
    /**
     * 生成略缩图.
     *
     * @param string $srcFile      源图片
     * @param string $dstFile      略缩图保存位置
     * @param int    $dstW         略缩图宽度
     * @param string $dstH         略缩图高度
     * @param string $isProportion 略缩图是否等比略缩,默认为false
     *
     * @return array|bool
     */
    public static function makeThumb($srcFile, $dstFile, $dstW, $dstH, $isProportion = false)
    {
        if (false === ($minitemp = self::getThumbInfo($srcFile, $dstW, $dstH, $isProportion))) {
            return false;
        }
        list($imagecreate, $imagecopyre) = self::getImgcreate($minitemp['type']);
        if (!$imagecreate) {
            return false;
        }
        $imgwidth = $minitemp['width'];
        $imgheight = $minitemp['height'];

        $srcX = $srcY = $dstX = $dstY = 0;
        if (!$isProportion) {
            $dsDivision = $imgheight / $imgwidth;
            $fixDivision = $dstH / $dstW;
            if ($dsDivision > $fixDivision) {
                $tmp = $imgwidth * $fixDivision;
                $srcY = round(($imgheight - $tmp) / 2);
                $imgheight = $tmp;
            } else {
                $tmp = $imgheight / $fixDivision;
                $srcX = round(($imgwidth - $tmp) / 2);
                $imgwidth = $tmp;
            }
        }
        $thumb = $imagecreate($minitemp['dstW'], $minitemp['dstH']);

        if (function_exists('imagecolorallocate') && function_exists('imagecolortransparent')) {
            $black = imagecolorallocate($thumb, 0, 0, 0);
            imagecolortransparent($thumb, $black);
        }
        $imagecopyre($thumb, $minitemp['source'], $dstX, $dstY, $srcX, $srcY, $minitemp['dstW'], $minitemp['dstH'], $imgwidth, $imgheight);
        self::makeImg($minitemp['type'], $thumb, $dstFile);
        imagedestroy($thumb);

        return array('width' => $minitemp['dstW'], 'height' => $minitemp['dstH'], 'type' => $minitemp['type']);
    }

    /**
     * 给图片制作水印.
     *
     * 水印的位置可以为：
     * <code>
     * array(0 => '随机位置', 1 => '顶部居左', 2 => '顶部居中', 3 => '顶部居右', 4 => '底部居左', 5 => '底部居中', 6 => '底部居右', 7 => '中心位置')
     * </code>
     *
     * @param string    $source       图片的源文件
     * @param int|array $waterPos     水印的位置,可以选择从0-7或是制定开始位置x,y,默认为0，随机位置
     * @param string    $waterImg     作为水印的图片,默认为空
     * @param string    $waterText    作为水印的文字,默认为空
     * @param array     $attribute    文字水印的属性，只对文字水印有效
     *                                <code>
     *                                array(0 => '字体文件'，1 => '系统编码', 2 => '字体颜色'， 3 => '字体大小')
     *                                </code>
     * @param string    $waterPct     水印透明度，从0到100，0完全透明，100完全不透明，默认为50
     * @param string    $waterQuality 图片质量--jpeg，默认为75
     * @param string    $dstsrc       目标文件位置，默认为null即不保存
     *
     * @return bool
     */
    public static function makeWatermark($source, $waterPos = 0, $waterImg = '', $waterText = '', $attribute = '', $waterPct = 50, $waterQuality = 75, $dstsrc = null)
    {
        $sourcedb = $waterdb = array();
        if (false === ($sourcedb = self::getImgInfo($source))) {
            return false;
        }
        if (!$waterImg && !$waterText) {
            return false;
        }
        imagealphablending($sourcedb['source'], true);
        if ($waterImg) {
            $waterdb = self::getImgInfo($waterImg);
            list($wX, $wY) = self::getWaterPos($waterPos, $sourcedb, $waterdb, 1);
            if ($waterdb['type'] == 'png') {
                $tmp = imagecreatetruecolor($sourcedb['width'], $sourcedb['height']);
                imagecopy($tmp, $sourcedb['source'], 0, 0, 0, 0, $sourcedb['width'], $sourcedb['height']);
                imagecopy($tmp, $waterdb['source'], $wX, $wY, 0, 0, $waterdb['width'], $waterdb['height']);
                $sourcedb['source'] = $tmp;
            } else {
                imagecopymerge($sourcedb['source'], $waterdb['source'], $wX, $wY, 0, 0, $waterdb['width'], $waterdb['height'], $waterPct);
            }
        } elseif ($waterText) {
            list($fontFile, $charset, $color, $waterFont) = self::checkAttribute($attribute);
            empty($waterFont) && $waterFont = 12;
            $temp = imagettfbbox($waterFont, 0, $fontFile, $waterText); //取得使用 TrueType 字体的文本的范围
            $waterdb['width'] = $temp[2] - $temp[6];
            $waterdb['height'] = $temp[3] - $temp[7];
            unset($temp);
            list($wX, $wY) = self::getWaterPos($waterPos, $sourcedb, $waterdb, 2);
            if (strlen($color) != 7) {
                return false;
            }
            $R = hexdec(substr($color, 1, 2));
            $G = hexdec(substr($color, 3, 2));
            $B = hexdec(substr($color, 5));
            self::changeCharset($charset) && $waterText = mb_convert_encoding($waterText, 'UTF-8', $charset);
            imagettftext($sourcedb['source'], $waterFont, 0, $wX, $wY, imagecolorallocate($sourcedb['source'], $R, $G, $B), $fontFile, $waterText);
        }
        $dstsrc && $source = $dstsrc;
        self::makeImg($sourcedb['type'], $sourcedb['source'], $source, $waterQuality);
        isset($waterdb['source']) && imagedestroy($waterdb['source']);
        imagedestroy($sourcedb['source']);

        return true;
    }

    /**
     * 文字水印的属性设置过滤.
     *
     * 返回为：
     * <code>
     *   array(0 => '字体文件'，1 => '系统编码', 2 => '字体颜色'， 3 => '字体大小')
     * </code>
     *
     * @param array $attribute 设置的属性
     *
     * @return array
     */
    private static function checkAttribute($attribute)
    {
        $attribute = is_string($attribute) ? array($attribute) : $attribute;
        if (!isset($attribute[1]) || !$attribute[1]) {
            $attribute[1] = 'UTF-8';
        }
        if (!isset($attribute[2]) || !$attribute[2]) {
            $attribute[2] = '#FF0000';
        }
        if (!isset($attribute[3]) || !$attribute[3]) {
            $attribute[3] = 12;
        }

        return $attribute;
    }

    /**
     * 判断是否需要转编码
     *
     * 判断依据为，编码格式为utf-8
     *
     * @param string $charset 编码方式
     *
     * @return bool
     */
    private static function changeCharset($charset)
    {
        $charset = strtolower($charset);

        return !in_array($charset, array('utf8', 'utf-8'));
    }

    /**
     * 获得打水印的位置.
     *
     * 如果传入的是数组，则两个元素分别为水印的宽度x和高度y
     *
     * @param int|array $pos      获得水印的位置
     * @param array     $sourcedb 原图片的信息
     * @param array     $waterdb  水印图片的信息
     * @param int       $markType 水印类型，1为图片水印，2为文字水印
     *
     * @return array
     */
    private static function getWaterPos($waterPos, $sourcedb, $waterdb, $markType)
    {
        if (is_array($waterPos)) {
            return $waterPos;
        }
        $wX = $wY = 0;
        switch (intval($waterPos)) {
            case 0:
                $wX = rand(0, ($sourcedb['width'] - $waterdb['width']));
                $wY = $markType == 1 ? rand(0, ($sourcedb['height'] - $waterdb['height'])) : rand($waterdb['height'], $sourcedb['height']);
                break;
            case 1:
                $wX = 5;
                $wY = $markType == 1 ? 5 : $waterdb['height'];
                break;
            case 2:
                $wX = ($sourcedb['width'] - $waterdb['width']) / 2;
                $wY = $markType == 1 ? 5 : $waterdb['height'];
                break;
            case 3:
                $wX = $sourcedb['width'] - $waterdb['width'] - 5;
                $wY = $markType == 1 ? 5 : $waterdb['height'];
                break;
            case 4:
                $wX = 5;
                $wY = $markType == 1 ? $sourcedb['height'] - $waterdb['height'] - 5 : $sourcedb['height'] - 5;
                break;
            case 5:
                $wX = ($sourcedb['width'] - $waterdb['width']) / 2;
                $wY = $markType == 1 ? $sourcedb['height'] - $waterdb['height'] - 5 : $sourcedb['height'] - 5;
                break;
            case 6:
                $wX = $sourcedb['width'] - $waterdb['width'] - 5;
                $wY = $markType == 1 ? $sourcedb['height'] - $waterdb['height'] - 5 : $sourcedb['height'] - 5;
                break;
            default:
                $wX = ($sourcedb['width'] - $waterdb['width']) / 2;
                $wY = $markType == 1 ? ($sourcedb['height'] - $waterdb['height']) / 2 : ($sourcedb['height'] + $waterdb['height']) / 2;
                break;
        }

        return array($wX, $wY);
    }

    /**
     * 获得略缩图的信息.
     *
     * @param string $srcFile      源文件
     * @param int    $dstW         目标文件的宽度
     * @param int    $dstH         目标文件的高度
     * @param bool   $isProportion 是否定比略缩
     *
     * @return array|bool
     */
    private static function getThumbInfo($srcFile, $dstW, $dstH, $isProportion = false)
    {
        if (false === ($imgdata = self::getImgInfo($srcFile))) {
            return false;
        }
        if ($imgdata['width'] <= $dstW && $imgdata['height'] <= $dstH) {
            return false;
        }

        $imgdata['dstW'] = $dstW;
        $imgdata['dstH'] = $dstH;
        if (empty($dstW) && $dstH > 0 && $imgdata['height'] > $dstH) {
            $imgdata['dstW'] = !$isProportion ? $dstH : round($dstH / $imgdata['height'] * $imgdata['width']);
        } elseif (empty($dstH) && $dstW > 0 && $imgdata['width'] > $dstW) {
            $imgdata['dstH'] = !$isProportion ? $dstW : round($dstW / $imgdata['width'] * $imgdata['height']);
        } elseif ($dstW > 0 && $dstH > 0) {
            if (($imgdata['width'] / $dstW) < ($imgdata['height'] / $dstH)) {
                $imgdata['dstW'] = !$isProportion ? $dstW : round($dstH / $imgdata['height'] * $imgdata['width']);
            }
            if (($imgdata['width'] / $dstW) > ($imgdata['height'] / $dstH)) {
                $imgdata['dstH'] = !$isProportion ? $dstH : round($dstW / $imgdata['width'] * $imgdata['height']);
            }
        } else {
            $imgdata = false;
        }

        return $imgdata;
    }

    /**
     * 获得图片的信息,返回图片的源及图片的高度和宽度.
     *
     * @param string $srcFile 图像地址
     *
     * @return array|bool
     */
    public static function getImgInfo($srcFile)
    {
        if (false === ($imgdata = self::getImgSize($srcFile))) {
            return false;
        }
        $imgdata['type'] = self::getTypes($imgdata['type']);
        if (empty($imgdata) || !function_exists('imagecreatefrom'.$imgdata['type'])) {
            return false;
        }
        $imagecreatefromtype = 'imagecreatefrom'.$imgdata['type'];
        $imgdata['source'] = $imagecreatefromtype($srcFile);
        !$imgdata['width'] && $imgdata['width'] = imagesx($imgdata['source']);
        !$imgdata['height'] && $imgdata['height'] = imagesy($imgdata['source']);

        return $imgdata;
    }

    /**
     * 获得图片的类型及宽高.
     *
     * <pre>
     * 图片type：
     * 1 = GIF，2 = JPG，3 = PNG，4 = SWF，5 = PSD，6 = BMP，7 = TIFF(intel byte order)，8 = TIFF(motorola byte order)，9 = JPC，10 = JP2，
     * 11 = JPX，12 = JB2，13 = SWC，14 = IFF，15 = WBMP，16 = XBM
     * </pre>、
     *
     * @param string $srcFile 图像地址
     * @param string $srcExt  图像后缀，默认为null则将会从图片地址中分析获取
     *
     * @return array|bool 返回图像的类型及高度和宽度
     */
    private static function getImgSize($srcFile, $srcExt = null)
    {
        empty($srcExt) && $srcExt = strtolower(substr(strrchr($srcFile, '.'), 1));
        $srcdata = array();
        $exts = array('jpg', 'jpeg', 'jpe', 'jfif');
        in_array($srcExt, $exts) && $srcdata['type'] = 2;
        if (false === ($info = getimagesize($srcFile))) {
            return false;
        }
        list($srcdata['width'], $srcdata['height'], $srcdata['type']) = $info;
        if (!$srcdata['type'] || ($srcdata['type'] == 1 && in_array($srcExt, $exts))) {
            return false;
        }

        return $srcdata;
    }

    /**
     * 获得创建图像的方法.
     *
     * @param string $imagetype 图片类型
     *
     * @return array
     */
    private static function getImgcreate($imagetype)
    {
        if ($imagetype != 'gif' && function_exists('imagecreatetruecolor') && function_exists('imagecopyresampled')) {
            return array('imagecreatetruecolor', 'imagecopyresampled');
        }
        if (function_exists('imagecreate') && function_exists('imagecopyresized')) {
            return array('imagecreate', 'imagecopyresized');
        }

        return array('', '');
    }

    /**
     * 创建图像.
     *
     * @param string   $type     图像类型
     * @param resource $image    图像源
     * @param string   $filename 图像保存名字
     * @param int      $quality  创建jpeg的时候用到，默认为75
     *
     * @return bool
     */
    private static function makeImg($type, $image, $filename, $quality = '75')
    {
        $makeimage = 'image'.$type;
        if (!function_exists($makeimage)) {
            return false;
        }
        if ($type == 'jpeg') {
            $makeimage($image, $filename, $quality);
        } else {
            $makeimage($image, $filename);
        }

        return true;
    }

    /**
     * 图片的对应类型.
     *
     * @param int $id 图片类型ID
     *
     * @return string
     */
    private static function getTypes($id)
    {
        $imageTypes = array(1 => 'gif', 2 => 'jpeg', '3' => 'png', 6 => 'bmp');

        return isset($imageTypes[$id]) ? $imageTypes[$id] : '';
    }
}
